package edu.usc.csci578.manager;

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import edu.usc.csci578.algorithm.*;
import edu.usc.csci578.model.*;
import edu.usc.csci578.util.ModelParser;

public class AlgorithmManager 
{
	private static AlgorithmManager am;

	public static AlgorithmManager getInstance() 
	{
		if (am == null) {
			am = new AlgorithmManager();
			new ConnectorEnvyAlgorithm();
			new DependencyMeshAlgorithm();
		}
		return am;
	}

	private Map<String, AbstracAlgorithm> algorithmsMap = null;
	private Set<AbstracAlgorithm> executeQueue = null;
	
	private AlgorithmManager() {
		clear();
	}

	public void clear()
	{
		algorithmsMap = new LinkedHashMap<String, AbstracAlgorithm>();
		executeQueue = new HashSet<AbstracAlgorithm>();
	}

	public boolean registerAlgorithm(AbstracAlgorithm algorithm)
	{
		if(algorithm == null)
			return false;
		algorithmsMap.put(algorithm.getName(), algorithm);
		return true;
	}

	public AbstracAlgorithm getAlgorithmByName(String name)
	{
		return algorithmsMap.get(name);
	}
	
	public List<AbstracAlgorithm> getAlgorithmsByDescription(String regex)
	{
		Pattern p = Pattern.compile(regex);
		List<AbstracAlgorithm> list = new  ArrayList<AbstracAlgorithm>();
		
		for(AbstracAlgorithm alg : getAllAlgorithms())
		{
			if(p.matcher(alg.getDescription()).find())
				list.add(alg);
		}
		return list;
	}
	
	public List<AbstracAlgorithm> getAllAlgorithms()
	{
		return new  ArrayList<AbstracAlgorithm>(algorithmsMap.values());
	}
	
	public void putInQueue(AbstracAlgorithm algorithm)
	{
		executeQueue.add(algorithm);
	}
	
	public void putAllInQueue()
	{
		executeQueue.addAll(algorithmsMap.values());
	}
	
	public void putInQueue(Collection<AbstracAlgorithm> algorithms)
	{
		executeQueue.addAll(algorithms);
	}
	
	public void removeOutOfQueue(AbstracAlgorithm algorithm)
	{
		executeQueue.remove(algorithm);
	}
	
	public void removeOutOfQueue(Collection<AbstracAlgorithm> algorithms)
	{
		executeQueue.removeAll(algorithms);
	}
	
	public void execute()
	{
		for(AbstracAlgorithm alg : executeQueue)
			try
			{
				alg.execute(System.out);
			} catch (Exception e)
			{
				e.printStackTrace();
			}
	}
	
	public void execute(AbstracAlgorithm algorithm) throws Exception
	{
		algorithm.execute(System.out);
	}
	
	public void execute(List<AbstracAlgorithm> algorithms) throws Exception
	{
		for(AbstracAlgorithm alg : algorithms)
			alg.execute(System.out);
	}
}
	